All right.
Now that we've completed our loading screen and camera scripts, we now need to focus on creating the
functionality for our GUI.
However, before we can start scripting the GUI itself, we need to set up the server service on the
server to allow players to create custom servers that other players can join.
So in Server script service, we're going to have our own custom service.
In here we're going to call it server service.
And this service is basically going to act as a class for us, where we'll be able to create new server
objects that keep track of who is inside the server, whether the server has a password, and a whole
bunch of other functions.
Now, before we get started, I want to create a standard for communication between the client and the
server, and we can do so by creating our own enumeration.
So unreplicated storage.
There is a section of modules here where I've created a custom enum.
And this is called server action enums.
And this server action enum is going to store the different strings that will represent the different
actions that the client can request the server to do, and the actions the server wants the client to
do.
So what we can do here is we can create a table.
I'm going to call it enum.
And inside of this table we're going to have two different key value pairs.
One is going to be a table for actions to the server.
So we'll call it two server.
And another table is going to be actions for the client.
So we'll call it two client.
Now some of the actions the client will make to the server are going to be things like creating a server.
So we'll call it create server.
And we'll just set it equal to a string of create server.
Another action would be like deleting a server.
Another action would be to get all the servers that currently exist.
So when a player joins one of these servers or one of these lobbies, they can grab all of the servers
that currently exist and then display that in their GUI.
We can make a request to join a server.
We can make a request to submit a password to a server.
So we call it.
We could call it a submit password.
The owner of the server can request to the server to, let's say, remove a player from a server.
And a player that's already inside of the server can also request to leave a server.
The last action that could be requested would be the owner of the server wanting to start the game,
so we could call it Start Server.
Now, some actions that the server could make to the client would be things like telling them to add
a server to the server list.
We could tell the client to remove a server from the server list.
We could tell the client to add a player to a server, so we could call it add player to list or add
to player list.
We could tell the client to remove a player from the player list.
We could tell a player that they were maybe removed from a server.
So if the owner of the server kicks them out, we can give them a message so we can do like removed
from server.
We could tell a player to update the server count for a server.
So when other players are joining a server, we want to update the server count on their end so we could
call it update server count.
And last but not least, we could tell the player that they are going to be teleporting.
So let's say the owner of the server starts the game.
We need to teleport them to the next place and to make it look more seamless, we can tell the client
to fade you know, a guy or a frame on the screen that says teleporting, so we can tell them that they're
about to be teleported.
So we can just call this command teleport.
So these are the different actions that the clients can request to the server.
And these are the different actions that the server can tell the client to do.
And then we can return this enum at the end.
And another interesting thing that we could do is we could actually set a meta table on this enum.
And what I'm going to do is I'm going to create an underscore underscore index meta method in here and
set it equal to a lambda function.
Now as we know, this meta method is only going to get called when we try to index this table with a
key that does not exist.
So let's say we try to index an action in two server that did not exist.
Well this meta method would get called.
And what we could do in here is we could just put out an error saying whatever they tried to index,
uh, is not a valid member instead of returning nil.
Because, you know, when we index a table with a key that does not exist, we're just going to get
nil.
But we could also instead have the script error when the player tries to request a key that does not
exist.
So this function gets passed the table itself.
And the key that the player tried to index with.
And what we could do is we could just raise an error here and put a string like percentage s.
So our directive is not a valid member of percentage s.
And we're going to format this with uh the key of course.
So we're going to convert this key to a string.
And then we're just going to use the scriptname.
So basically if we try to index like two server or two client with something that doesn't exist, it'll
error say this key is not a valid member of server action enums.
So now that we have this complete, we can go ahead and go into our server service.
And the services that we're going to need in here is going to be the player service.
We are going to need replicated storage.
We're going to need the teleport service.
And then I'm also going to use the Http service to give different servers or the servers that are created
by the service, a custom or unique ID.
Now let's go ahead and set up the tables for this service.
We're just going to call this table Server service.
And then we're also going to have a meta table for objects created by this service.
So we can just call it server service MT.
Server service MT we're going to set the underscore underscore index meta method to itself.
And then what we're also going to do is we're going to set the underscore underscore new index meta
method.
Equal to a function.
And what this is going to do is just going to error, and it's going to give out a message that says
unable to add new index to object.
So if any script attempts to try to add a new key value pair to our objects, we're going to error because
we only want to add whatever is created by our constructor.
Now some other variables we're going to need is we're going to need a reference to this server event
or this remote function and replicated storage.
So we can call it server event is equal to replicated storage, dot events, dot remotes, dot server
event.
And this is the remote function we're going to use for the client to communicate with the server.
We're going to have another event.
We're going to call update GUI event.
And we're going to use this event to tell our clients to update their GUI when needed.
And last but not least, we're also going to require our server action enums.
So server action enums.
Then replicated storage in the modules folder.
Get the enum of server action enums.
And because we've created our own custom enums, that means we're able to change these values to represent
whatever we'd like, instead of having to go into each script to change whatever these values are.
We can just do it from this one script.
Now we're going to create another table to act as the cache for all the servers in this game.
So it's just going to store all the current servers.
And I'm also going to create another table and I'm going to call it Server private.
And when the purpose of this table is to store all the passwords for any servers.
So instead of storing the password in the server object itself, we want to store the password in this
private table here.
That way we're not able to see it from the object.
And when the players request to see all the servers in the game, they're not going to be able to see
the passwords for them either.
And then last but not least, we're going to create a constant here.
And this constant is going to represent the ID for the other place in our game where we're going to
teleport the players to.
So I'm just going to call it start place ID, and I'm just going to set it for one for now.
But when we create our next place in the game, we're going to want to copy the ID of that place and
paste it in here.
Now, the first private function I want to make is a function to see if an argument matches a particular
type, so we can call it arg matches type.
It'll take an argument, which is anything.
And we want it to match an expected type, which will be a string, and this function will return back
a boolean.
And this function is actually going to be pretty simple.
So the first thing that we could do is if this type of expected type is not equal to a string.
So basically whoever is using this function did not pass the correct, uh, data type to this parameter.
We're just going to error and just say expected type string for expected type.
But we got something else instead.
And then we could go ahead and format this.
Call the format function on it and pass the type of expected type.
Now, if the type of our argument is not equal to an instance.
So we don't want to check the class, but we want to check the type.
And let's say the type of argument is not equal to the expected type.
Then we're going to return false or aka.
This argument does not match our expected type.
However, let's say the type of this argument is an instance.
So let's say it's an instance.
Then we need to make sure that this argument matches the class that we expect.
So if it doesn't.
So let's say this argument is not of the class expected type.
Whatever that type is, then we're also going to return false.
Otherwise we could just return true.
Now, some other functions we're going to need in here is one to check if a player exists already in
a server, so we can just call it is player in server.
We'll have a function to listen when a player is removed from the game, so we can call it on player
removing.
We're also going to have a function to connect to our server event.
So we can call this on an event invoke.
And this just expects a player, an action from that player and any arguments to go with that action.
And then we can go down to this public function section here and create the constructor for our service.
So this function in our server service.
His first going to need an owner.
So we're going to need an owner for a server, right.
Who's going to be the owner of the server?
We're also going to need the maximum size of the server.
So we can just call it max.
Size is going to be a number.
Will have a parameter of whether or not this thing has a password, so has password.
It'll be a boolean.
And then if it does have a password, then we can just pass that password to be the last argument.
So it could be a potential string here.
Some other functions that I want to have to be a part of this service would be to get a server based
on the owner.
So let's say we pass a player, we want to check to see if that player owns a server.
So in server service we can create a function like a get server from owner.
And this would get passed a player object.
We could just call it an owner and it would just be passed a player.
Or we could get passed a string which could be the name of an owner.
Now down here is going to be all the functions that are going to be attached to our meta table or aka,
these are going to be all the functions that are going to be a part of the server objects themselves
and not the class.
So inside of our server service meta table, what's a function we want to have for our server?
Well, we want to be able to add a player to a server.
We want to be able to remove a player from a server.
We want to be able to, let's say, add a player to a whitelist in a server.
So basically if a server has a password, then when a player submits a password, we can check whether
or not that password was correct.
If the password was correct, then we could add that player to a whitelist, which allows them to join
the server.
So we could call this function here something like.
We call it something like AD player.
To whitelist.
And we could also have a function to remove a player from a white list.
So let's say a player joins a password protected server, but then the owner kicks them.
Then we want to remove them from the white list.
We also want to have the ability to, let's say, lock a server, which prevents any players from joining
it or leaving it.
And this will be very useful for when we have to teleport all of the players in the server.
And we could also have one for unlocking a server as well.
Lastly, we'll need a function for destroying a server.
So server service meta table.
We want to have the ability to destroy a server.
Now for this particular service here.
All we need to do is we need to have a function for initializing this service or aka we just want to
connect our function to the different events.
So we could do function server service init.
So initializing the service what we want to do is we want to reference our server event.
And on server invoke can be equal to our on event invoke function.
And then for players dot player removing we can connect that on player removing function.
And that's all we need to do for this initialized section of this service.
And I don't believe we need to start the service, because all it's going to do is listen to these events.
And then at the very end here, we want to make sure to return our server service table.
Okay, so the first thing I think we could fill out here is the constructor for our server service.
So we want to be able to create new server objects.
Before we do anything in this server service, we need to verify the information that is being passed
to our constructor, because this constructor is going to be called when players request to create a
server.
We have no idea what the client is going to be sending to us.
All right?
An exploiter could be sending us random garbage to our constructor and it will cause errors in our script.
So a good practice would be to verify that the information being sent here is correct.
So the first thing we could do is let's say this argument does not match our type of player.
So for the owner, if this is not a player, then we need an error or otherwise we can just return false
and send a message back to the player or the client and tell them something like expected player.
Her owner, but we got or we could say got put a directive here instead.
And we're going to format this string with the type of the owner that was passed to this constructor.
So basically the idea is we're going to be returning a boolean and a string back to the client through
our server event, and they can display this message on our screen.
So that way it can be easy to show the player what went wrong when creating their server or giving them
any messages.
And it also makes it easy for us to debug anything in case something wrong happens.
The next thing we need to check is this max size.
So if this argument doesn't match the type of number, then we also need to return false.
And we can say expected number.
For max size, but we got percentage s instead.
And again we're going to format this with the type of max size.
And we can just basically copy this paste it here.
But instead we're going to do it for has password.
And this has to be a boolean.
So we expected a boolean.
For has password, but we got whatever they passed instead.
And again, we'll do this one last time for the password itself.
So if has password is true.
And let's say.
Um, this does not match the argument.
So.
We'll pass the password here and it has to be of the type string.
Expected string for our password.
Expected string for our password, but we got whatever was passed instead.
And that looks pretty good there.
And you can kind of see how these if statements all read out like basic English.
So if this if not ARG matches type owner player then we return false.
If not uh max size matches number, then we returns false and so on.
Once we have verified that all of the information passed to our constructor is good, then we could
create a new server object.
So I'm going to override self with a new table.
We can set the key value pair of owner in this table to be equal to the owner.
We could set the has password property equal to has password.
We could set the max size equal to max size.
And then we'll have a table in here.
We'll call it players and server.
And this is going to keep track of all the players that are a part of this particular server object.
And of course the first player is obviously going to be the owner.
And that should be the case when we create a new service, just the owner.
We're also going to be creating a table for the white list that will just store all the players cleared
for entry.
For the server, we'll have a property called locked, which will keep track of whether or not it's
locked.
And then last but not least, we'll have a custom ID for the server using the Http service.
And we're going to generate a new UID.
Now, if self dot has password is true, then what we're going to do is we're going to create a table
in here.
I'm going to call it private.
And inside this uh, private table we're going to have a key value pair of password.
And it's going to be simply equal to the password that was passed to our constructor.
Then once we've created this table, we can store it within the server private table that we created
earlier.
And we're going to use the ID of the server as the key for this table.
And then we could just set it equal to this private table that we just created.
So at any point in the future when we need to check the password for a particular server, we just check
our server private table, pass the ID of that server, and then we can get the private table that stores
the password for this particular table.
Once we have finished doing all of that, then we can insert this table inside of our current servers
table.
And then we can set the meta table of this table to our server service meta table.
And the reason we're doing this last is because we have overridden the new index here to error.
So if we set the amount of table the first thing before we started creating all these key value pairs
here it would error of course.
So we need to do it at the very end.
And then we could just basically just return this.
At the end of our constructor, so we'll just return true that everything went well and then we return
the object.
Now let's go ahead and fill out some of these other basic functions we have in here, like a get server
from owner.
This one should be pretty easy.
All we need to do is we need to loop through every single server object that is inside of our current
servers table, and all we need to do is we need to check if the server dot owner is equal to the owner
passed to this function, or if the server dot owner dot name is equal to the owner passed to this function
because it could be either a player or a string.
If it matches, then we can just return the server and that's it.
All right.
So the next function we can fill out is adding a player to a server.
So we can pass to this function the player we wish to add to the server.
And this function can return back to us a boolean and a string.
Because the plan is here.
Let's say, uh, we request to join a server and we get added.
Then we can get a message sent back to us, like we successfully joined the server, or we could get
sent a message back to us, like, the server is full or the server is locked or something like that.
So let's go ahead and verify that first of all.
So let's say if the server is locked so self dot locked then we're going to return false and tell the
player that the server is locked.
If the number of people in the server.
So we're going to check the length of our players and server table if that's equal to self dot max size,
then we're also going to return false.
And we're going to say that the server is full.
Now let's say that the player is already in a server, but they're an exploiter and they're trying to
mess with our functions and our remote events, and they're trying to join multiple different servers.
So what we need to do is we need to verify that they're not in a server.
So if, uh, is player and server.
So let's say this player we want to add is in the server, then we need to return false and say you
are already in a server.
That means we can go ahead and fill out this function here.
So let's scroll up.
And we'll pass a player to this function.
And what we could do is we could loop through every single server in our current servers table.
And what we could do is we could check if this player is inside of this server.
Dot players in server.
If they are, then we could do something like return the server, and once we're done looping and we
didn't find them, we could just return false.
So that means when this function gets called right here, if this player is on a server, it'll return
the server back to this point.
And since we're checking it in a condition, it'll evaluate to true and it'll return false and tell
them that they're already in a server.
Uh, another thing we need to check is whether or not the server has a password.
So if self dot has password.
And let's say that this player is not within the white list for the server.
So not table dot find and self dot white list player to add.
Then we need to return false and tell them you must submit the correct password to join this server.
Otherwise, once we have verified that all the information is correct, then we can loop through every
single player that is inside of this server.
So self dot players in server.
And what we could do is we could use our update guy event to fire to those players that they need to
add a new player to the server's player list so we could fire client.
To this particular player and using the server actions enums to client, we could tell them to add to
player list.
And who do we want to add?
Well, we want to add this particular player here.
And then once that's done, we can insert this newly added player into our self dot players and server
table.
And then we'll fire to all of the clients in our game that we want them to update the server count for
a particular server so we can do server actions, enums, dot two, client update, server count, and
we want to update the server count for self or this particular server object here.
And then once we've done that we can just return true and say something like joined server.
Okay, so what do we want to do for removing a player from the server?
Well, we can create a parameter.
We can call it player to remove.
And this is going to be a player.
And we can also return a boolean.
And a string from this function.
What we need to do is, of course check whether or not the server is locked.
So if self dot locked then return false and say something like server is locked.
Otherwise, the next thing we need to check is whether or not this player we want to remove is actually
in the server.
So what I'm going to do is I'm going to use the table dot find function to get the index in our players
in server table, we want to find what index this player is.
So we'll create a variable called I.
And let's say there is no index or basically this player doesn't exist in the server, then we can just
return false and say player is not in server.
Otherwise we can remove this player from our self-taught players and server.
And pass that index there.
And actually, another thing that I want to add here is I want to have another parameter.
We're going to call it removed by owner.
It's going to be a boolean.
And basically when this function gets called we want to see if this function was called by a player
who voluntarily was removed from the server, or if they were removed by the owner.
So if they were removed by the owner, if this particular player was removed by the owner, then we
want to give them a message telling them something like, you were kicked from the server so we could
use the update guy event and fire to this particular client player to remove, and we can tell them
that they were removed from the server so we could do server actions.
Enum.
To client and the action is removed from server.
And we can tell them a message like you have been kicked from the server.
Otherwise, we can just give them a message like you left the server so we could basically do the exact
same thing here, but give them a different message, like you left the server.
So we just want to give a different message based on whether or not they were removed by the owner.
The next thing we need to check is if the server has a password.
So if as password then we need to remove them from the white list.
So we can call that remove player from white list function and pass the player.
And we'll fill this function out in a second.
And then we can loop through every single player in ipairs self, dot players and server and tell them
to remove a particular player from the player list so we can use our update guy event fire to this particular
client.
Give them the action.
Of remove from player list.
And who do you want to remove from the player list?
Well, this particular player.
And then once that's done, we can use the update event again and fire to all of the players in our
game that we want them to update the server count for a particular server.
So two client update server count and it's going to be for the server.
Then we can return true and say something like player removed.
So let's go ahead and fill out these two functions here.
Add player to whitelist and remove player from whitelist.
So for this first one, this will just take a player.
And basically all we need to do here is just insert this player into the self dot whitelist table.
And that's it.
And then for remove player from whitelist, all we need to do is get the index where this player resides
within the whitelist.
And we'll get a player pass to this function.
So if they are inside of our whitelist table then we can just remove them.
And that's all we need to do there.
Let's go ahead and actually fill out these two functions as well, because this should be pretty easy.
All we need to do is set self dot lock to true.
And here set self dot lock to false.
And that's it.
Now for destroying a server.
We need to do a few things.
First, we need to loop through every single player that is inside of this server.
So self dot players in server.
Well, we need to do is we need to tell them that they were removed from the server because the server
is going to be deleted.
So we can use the update GUI event and fire to this particular player.
And we can give them the action of remove from server.
And we'll give them a message like the server was deleted.
Then we can update to all of the clients in our game to remove the server from the server list.
So server action enums to client dot remove server.
And the server is going to be self.
And then we can remove the server from our current servers table using table dot find to get the index
where it resides.
The next thing we need to do is to check to see whether or not the server had a key value pair within
our server private table.
So if server private self.id then we can just set this to nil.
And then last but not least, we can use the table dot clear function to clear out all the key value
pairs in this table, or basically free up all the memory.
And that's all we need to do for our destroy function.
So the last couple of things that we need to fill out is our on player removing and our on event invoke
functions.
So let's go ahead and do this one first because it should be pretty easy.
Remember this function gets called when a player is removed from the game.
So we'll get a player passed to this function.
And basically what we want to do is we want to check, um, if this player that is removed from the
game, uh, was the owner of a server.
So we could create a variable called server, and we're going to use the server service and use the
function get server from owner and pass this player.
So if this player was an owner of a server, then we need to destroy it.
So if server then server destroy and that's it.
The next thing we need to check is whether or not this player, uh, was inside of a server.
So they weren't the owner of the server, but they were inside of a server.
Then what we need to do is we need to use our Is player and server function and pass the player.
And we'll get a server back here.
So we'll just override this variable that we just created.
And if server.
Then we can just use the remove player function and pass this particular player.
Okay.
So this is the last function that we're going to go ahead and have to fill out.
And this one is going to be pretty long because we have to listen to all of the different actions that
the client can request the server to do.
So the first actions I want to check here are all of the actions that don't require any arguments to
be passed with them, because I want to be able to check afterwards whether or not this args uh variable
here is equal to a table, and if it isn't, then we just need to return false and say that we expected
a table here for the next actions.
But we didn't get it.
But what we can do here is first we can check the action of like server action enums dot two server
delete server.
So let's say a player wants to delete a server.
Then what we need to do is to check to see if they actually own a server.
So we're going to use the server service and get server from owner with this player.
If they do not own a server, then we need to return false and tell them something like you do not own
any servers.
Otherwise we can just destroy the server.
And then return true and say something like server deleted.
Another action we can check is like server action enums dot two server.
We could do the action of git servers and this one's pretty easy.
All we need to do is return all of the current servers.
And again we don't need any arguments for these.
Else if the action is equal to server action.
Enums dot two server.
And let's say the action is like a player wants to leave a server.
Then what we could do is we could see what server this player is in.
So server to leave is equal to is player and server and pass this player if not.
So let's say this player isn't in a server, then we're just going to return false and tell them you
are not in a server.
Let's say an exploiter owns a server, and for some reason they were messing with our remote function
and tried to leave a server while they were the owner of the server.
Then we need to make a check for that.
So if server to leave owner is equal to this player, then we're going to return false and tell them
you must delete the server.
You can't leave it, you have to delete it.
Otherwise we can go ahead and return the values from the remove player function so we can get this server
to leave and call the remove player function on it and pass this player.
And we're going to pass false for the second argument, because remember that boolean represents whether
or not this player was removed by the owner.
But since a player is requesting to leave the server, then this is going to be false.
Another action is going to be the server action enums to server dot start server.
So let's say the server owner wants to start the game.
Then what we could do is we could get the server that the owner wants to start.
So we're going to use the server service and get server from owner and pass this player.
If they do not own a server or aka.
This didn't return a server back to us, then we're going to return false and tell them you do not own
a server.
Otherwise we're going to lock the server so no player can join it or leave it.
And then we're going to start the server.
So in fact I don't think we actually made this function.
So we want to be able to start the game on a particular server.
So let's go ahead and scroll down here.
And we could just put it like somewhere, like right here and inside of our server service meta table,
we can create a function for starting a game.
And what we could do is we could loop through every single player in ipairs self, dot players and server,
and we want to tell them that they're about to be teleported.
So we could use the update guy event to fire to them.
That.
We want them to be teleported so we could use the server actions.
Enums.
Two client dot teleport.
And then we could just wait a random amount of time, like one second.
So that way they're not teleported instantaneously.
And what I'm going to do is I'm going to use a function in the teleport service called Reserve Server.
So actually let me get the teleport service.
And we're going to call the reserve server function.
And what this does is it returns an access code that can be used to teleport players to a reserved server.
So we need to pass an ID to this that represents the starting place, which will be our start place
ID at the moment it's just equal to one.
But when we create the next place, this is where they're going to be teleported to.
And this will return back to US data for the server, so we can just call it server data.
And then I'm going to create a variable called teleport data.
And this is going to be the data that I'm going to send to the other place.
So that way any server script in the other place can receive any information coming from this place.
So inside of this table I'm just going to create a key value pair.
And I'm going to call it expected players.
And it's going to be equal to the number of players that are inside of self dot players in server.
So we're letting this place know how many players to expect.
And then we can use the teleport service.
And there's a function in there called teleport to private server.
The place.
ID is going to be the start place ID.
The reserved server access code are basically.
The data for the server came from our reserved server function.
So we're going to pass our server data here.
The players we wish to teleport to the server are going to be all of the players in our players in server
table.
This next argument here is spawn name an optional name of the spawn location to spawn at.
So we're just going to pass the generic name of spawn location.
And then lastly, we need to pass any kind of teleport data that we need to pass or aka this table right
here.
So teleport data.
And that's all we need to do there.
So now this function is going to teleport all of our players to this, uh, server that we reserved
using this function right here.
And because we've done that, then we can go ahead and just destroy the server.
Okay, so back in our Onevent invoke function, we have fulfilled all of the different actions we needed
for ones that didn't require any arguments, but now all of the other or remaining actions need to have
arguments supplied to them.
So we need to verify whatever information is being passed from the client is correct.
So we need to make sure that this args parameter here is actually a table.
So if this args is not a table so arg matches type args table.
If it isn't a table, then we need to return false and give them a message like expected type.
Table for args, but we got whatever instead.
And we can format this string with the type of args.
This will stop any junk that is being passed to this function from exploiters.
And then we can go ahead and start listening to all the different actions that require arguments to
be passed to them.
So let's say the action is equal to server action enums dot two server dot create server.
So let's say player wants to create a server.
Well the first thing that we need to verify is if this player is in a server.
So if this player for some reason is in a server and they're somehow firing this event, then we need
to return false and tell them you cannot create a server while in a server.
The next thing we need to do is check whether or not the server is going to have a password.
So instead of args we want to have a key value pair of has password.
So if this table is going to have a password then we need to make sure whatever password they pass to
us is actually a string.
Right.
So if not arg matches type args dot password string, then we're going to return false and say something
like expected type string for password.
But we got whatever instead.
And we're going to format this with the type of args dot password.
Um, we also want to have some specific criteria for a password.
So we don't want it to be less than four characters, but we don't want it to be greater than 12 characters.
And of course, you can change that if you'd like.
But if the number.
Or the length of our password is less than four, or the length of our password is greater than 12,
then we need to return false and tell them something like password must be 4 to 12 characters long.
And that's all we need to do there.
Otherwise, the next thing that we could do is we could use our constructor to get the success and result
from it.
So server service dot new.
We're going to pass the player that requested to create the server because they're going to be the owner.
We're going to pass args dot max size args dot has password and args dot password.
And we're going to convert this password to uppercase.
That way it's consistent across the board.
And all of these different key value pairs are going to be the things that we're going to be passing
to this args table from the client.
So let's say we were not successful in creating a server.
Then what we need to do is we need to return success and the result message.
So like let's say the player for some reason somehow passed, you know, an incorrect type for max size.
Let's say an exploiter was messing with this function.
And we're just going to tell them, hey, you can't do that.
Otherwise.
If we were successful, then what we could do is we could loop through every single, um, player in
our game that's not the owner of the server.
So every single other player and I pairs players get players.
Um, if this player or if this other player is equal to the player that wanted to create the server,
then we're just going to continue looping and you'll see why in a moment.
Because what we're going to do is we're going to use the Updateui event and fire to this client to add
a server.
To the server list, it wouldn't make sense for the owner to add the server to the server list.
When they're the owner of it, they're not going to be able to see it, so there's no point.
So we're just going to fire to all the other players in the game.
We want them to add a server to the server list.
So we could use server action enums to client, and we could tell them to add a server.
And that server is going to be the result from our constructor, which is going to be our server object.
And once we finally done all of that, then we can just return true and tell this player that we successfully
created the server so we can just tell them server created.
And that's it for this particular action.
Now the next action we need to listen to is let's say they want to join a server.
So let's say a player wants to join a server.
So we can do two server.
Join server.
Then what we're going to do is we're going to basically just see if the server that this player wants
to join even exists.
Server to join is equal to server service.
And we're going to use the get server from owner function because the player is going to pass to us
the owner of the server that they want to join.
So we could do args dot owner.
If the server that they want to join does not exist.
Now we're going to return false and say server does not exist.
Otherwise, we're going to get the result from, uh, server to join AD player.
We're going to add this player to the server, and then we're just basically going to return success
results.
And then I also want to return the server itself as well.
And you may be wondering, well, why do you want to return the server object here.
Well, I want to do that because um, if the player does successfully join the server, then they want
to be able to loop through every single player that's already inside of the server and create, uh,
different player frames on their end to show all the different players that are in the server with them.
All right.
The next action that we can fill out is to, let's say, submit a password to the server.
So we could do server action enums dot two server submit password.
So let's say a server is password protected.
Then they need to submit a password for the server.
And again, this, uh, action needs to be supplied the server that this player is trying to submit
the password to.
So we can just call this server to join equal the server service.
Get server from owner.
And again we're going to do args dot owner.
If the server for some reason does not exist, then we're going to return false and say server does
not exist.
Otherwise, the next thing we could check to see is whether or not the server even actually has a password.
So if server to join.
That has password.
So let's say it doesn't have a password.
So if not has password then return false.
And we'll say something like server does not have a password.
Um, otherwise, the next thing we need to check is whether or not the password the player is supplying
to this action is the correct password.
So what we're going to do is we're going to use the string dot upper function to convert their password
to uppercase.
So that way again it stays consistent because when we create the password on the server we've made it
uppercase.
So, um, what we could do inside of ARGs, we can create a key value pair like submitted password.
This will be the password that the player submits.
And if this password does not match the password that is inside of our server private table.
And again we need to pass the server to join.id and then get the password.
So if the password does not match, then we're going to return false and say password was incorrect.
Otherwise.
Once we have finally verified all this information, then we can do server.
To join, we need to add this player to the white list for the server.
And then we're just going to return true and tell them that they were successful in submitting the correct
password.
All right, we're almost done here.
Just hold on to your horses.
If the action.
Is equal to server action enums dot two server dot remove player.
So let's say the owner wants to remove a player.
Then again we need to check the server that this player owns.
So server service get server from owner player.
If the player requesting this action for some reason doesn't own a server.
So if not a owner server, then we can return false and tell them you do not own any servers.
Otherwise we can get the player they wish to remove using the player service.
So players, and we're going to find the first child that matches the args dot player to remove.
So again we're going to create another key value pair.
In here.
We'll just store the string or the name of the player.
And we'll see if they exist within our player service.
If this player does not exist in our game, then we're going to return false and say player does not
exist in the game.
Otherwise we're going to use the owner server, um, and use the remove player function inside of it
and pass this player that we wish to remove.
And we're going to pass.
True.
Because again, we need to pass a boolean of whether or not this player is being removed voluntarily
or by the owner.
And then this function returns back to us, uh, a boolean and a string.
So we can just return that here at the end of this section of our if statement.
And I'm pretty sure that's actually all the actions we needed to fulfill.
Let's go ahead and verify that we have fulfilled all of those different ones.
Looks like we have.
So we have one, two, three, four, five, six, seven.
Eight different actions and we can count the number of actions here.
So there's four, five, six, seven, eight.
Cool.
We have successfully filled out all of the different actions that can be requested to the server.
If somehow we've reached it to the very end of this function, and the player's action did not match
any of the actions in here, then we're just going to return false and tell them requested action did
not match any possible actions.
And I think that's it.
I'm pretty sure.
Let's go ahead and verify.
We have everything that we needed filled out.
And it looks like we have.
Perfect.
So the next thing we need to do is we need to go ahead and fill out the local script that's going to
handle the GUI on the client, and that guy is going to handle all the different frames for the server
browser, or being the owner of the server and things like that.
And that script is also going to handle to fire, you know, different actions to the server for like
removing players from a server or joining a server and things like that.
So thanks for sticking through this longer lecture.
I know it was a little while, but I'll go ahead and see you in the next one.